﻿using Infrastructure.Lib.Core.Trilaterration.Strategy;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Infrastructure.Lib.Core.Trilaterration.Model
{
    public sealed class Floor
    {
        public class FloorNested
        {
            static FloorNested() { }

            internal readonly static Floor instance = new Floor();
        }


        #region Singleton

        public static Floor Instance
        {
            get
            {
                return FloorNested.instance;
            }
        }

        Floor()
        {
            _strategies = new List<AbstractStrategy>()
            {
                new TrilaterationStrategy(),
                new RayTracingStrategy(),
                new PowerCenterStrategy(),
                new EptaStrategy()
            };

            _usingStrategyIndex = 2;
        }

        #endregion

        private readonly List<AbstractStrategy> _strategies;

        private int _usingStrategyIndex;

        public List<BeconPrototype> Beacons { get; private set; }

        public List<PointF> UserPositions { get; private set; }

        public bool IsUsingBothStrategies { get; private set; }

        public string BeaconsAsString()
        {
            return Beacons.Aggregate("", (current, beacon) => current + ("(" + beacon.X + "; " + beacon.Y + "); Acc=" + beacon.Accuracy + "\n"));
        }

        public void Reset()
        {
            Beacons = new List<BeconPrototype>
            {
                new BeconPrototype {Accuracy = 1, X = 0.5f, Y = 0.5f},
                new BeconPrototype {Accuracy = 1, X = 2.5f, Y = 0.5f},
                new BeconPrototype {Accuracy = 1, X = 0.5f, Y = 2.5f}
            };
            UserPositions = new List<PointF>(3) { new PointF(-100, -100), new PointF(-100, -100), new PointF(-100, -100), new PointF(-100, -100) };
        }

        public void AddBeancon(string key, PointF position)
        {
            BeconManager.Instance[key] = new BeconPrototype(position);
        }

        public void ChangeTrilaterationMethod(int index)
        {
            IsUsingBothStrategies = false;
            _usingStrategyIndex = index;
        }

        public void UseBothMethods()
        {
            IsUsingBothStrategies = true;
        }

        public PointF CalculateUserPosition(List<LocationRadius> locations)
        {
            List<BeconPrototype> beacons = new List<BeconPrototype>();

            foreach (var loc in locations)
            {
                var protoype = BeconManager.Instance[loc.Key];
                if (protoype != null)
                {
                    var becon = protoype.Clone();
                    becon.Accuracy = loc.Radius;
                    beacons.Add(becon);
                }
            }

            return _strategies[_usingStrategyIndex].CalculateUserPosition(beacons);
        }

        public void CalculateUserPosition(List<BeconPrototype> beacons)
        {
            if (!IsUsingBothStrategies)
            {
                UserPositions[0] = _strategies[_usingStrategyIndex].CalculateUserPosition(beacons);
            }
            else
            {
                for (var i = 0; i < _strategies.Count; i++)
                {
                    UserPositions[i] = _strategies[i].CalculateUserPosition(beacons);
                }
            }
        }

    }
}
